【Tips】boto3のS3.ListObjectsで末尾のオブジェクト情報を一発で取得する
こんにちは。DA部の春田です。
表題の件について、Pythonのイテレータを使用した強力な手法を簡単にご紹介します。
問題
S3のオブジェクト情報を取得するのに、ListObjectsオペレーションはよく使用されるかと思います。AWS CLIの場合はaws s3 ls
、Pythonのboto3の場合はclient.list_objects_v2()
などが代表的ですね。
ただ、これらのオペレーションはオブジェクト名の昇順で値が返されるため、オブジェクト数が数万件もあると「末尾のオブジェクト情報だけでいいのに、一番上から取得してるの、なんて無駄なのかしら」と思っていた方いらっしゃるのではないでしょうか?
パラメータのPrefixやStartAfterで事前の絞り込みはできますが、取得順序を制御することはできませんし、boto3の場合1000件を超えるとContinuationToken
が必要になるので、ループ処理を書くのが面倒臭かったり。
解決策
そんな時は、resource('s3').Bucket('hoge').objects.all()
でイテレータを生成し、標準ライブラリのcollections.deque()
でイテレータの末尾を取得します。具体的には以下の通りです。
import boto3 from collections import deque # S3バケットhoge配下のオブジェクト一覧を取得するイテレータを生成 objects_iter = boto3.resource('s3').Bucket('hoge').objects.all() # イテレータの最後のオブジェクトを吐き出して、キーを取得する key = deque(objects_iter, maxlen=1).pop().key print('S3 tail object: {}'.format(key))
resource('s3').Bucket('hoge').objects.all()
で生成される list(s3.ObjectSummary)
はイテレータであり、呼び出されるタイミングでリクエストをかける仕様になっています。そのため、生成したイテレータの末尾にアクセスできれば、1回のリクエストで末尾のオブジェクト情報を取得することができます。
イテレータの末尾にアクセスするには、標準ライブラリcollections
のdeque
オブジェクトを使用します。maxlen
パラメータはUNIXでいうtail
コマンドのような役割も兼ねており、これを使用して長さ1、末尾データのみのdeque
オブジェクトを作成したところで、pop()
してs3.ObjectSummary
にアクセスします。
応用例として、例えばresource('s3').Bucket('hoge').objects.filter()
を使用すれば、様々な条件を指定した上でオブジェクト情報を取得することもできます。また、iter(deque(objects_iter, maxlen=100))
とすれば、末尾100件までのイテレータを生成し直すことができます。この方法は、itertoolsの拡張版パッケージmore-itertoolsでtail
メソッドとして実装されているので、こちらを使用するのもアリです。
API Reference — more-itertools 8.5.0 documentation
イテレータを扱う際deque
オブジェクトはかなり便利なので、ぜひ一度公式ドキュメントも見てみてください。
collections --- コンテナデータ型 — Python 3.8.5 ドキュメント